//
// Created by ECNU on 2024/2/22.
//

#include <nanofaiss/IndexFlat.h>

#include <nanofaiss/impl/FaissAssert.h>
#include <nanofaiss/utils/distances.h>
#include <nanofaiss/utils/Heap.h>

#include <cstring>

namespace faiss {

IndexFlat::IndexFlat(idx_t d, MetricType metric)
        : IndexFlatCodes(sizeof(float) * d, d, metric) {}

void IndexFlat::search(idx_t n, const float* x, idx_t k, float* distances, idx_t* labels) const {
    FAISS_THROW_IF_NOT(k > 0);
    //TODO: Not yet implemented
    switch (metric_type) {
        case MetricType::METRIC_INNER_PRODUCT:
            break;
        case MetricType::METRIC_COSINE:
            break;
        case MetricType::METRIC_L2:
            float_query_t qp{size_t(n), size_t(k), distances, labels};
            knn_L2sqr(x, get_xb(), d, n, ntotal, &qp);
            break;
            /*
        case MetricType::METRIC_L1:
            break;
        default:
            break;
             */
    }
}

void IndexFlat::sa_encode(idx_t n, const float* x, uint8_t* bytes) const {
    if (n > 0)
        memcpy(bytes, x, code_size * n);
}

void IndexFlat::sa_decode(idx_t n, const uint8_t* bytes, float* x) const {
    if (n > 0)
        memcpy(x, bytes, code_size * n);
}

void IndexFlatL2::sync_l2norms() {
    cached_l2norm.resize(ntotal);
    fvec_norms_L2sqr(
            cached_l2norm.data(),
            reinterpret_cast<const float*>(codes.data()),
            d,
            ntotal);
}

void IndexFlatL2::clear_l2norms() {
    cached_l2norm.clear();
    cached_l2norm.shrink_to_fit();
}

}
